package com.hao.proxy.core;

import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;

import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hao.proxy.config.ProxyConfig;
import com.hao.proxy.context.Constants;
import com.hao.proxy.crawler.AbstractCrawler;
import com.hao.proxy.enums.ProxyStatusEnum;
import com.hao.proxy.model.Proxy;
import com.hao.proxy.utils.Sleep;


public class ProxyCenter {
	
	private final static Logger logger = LoggerFactory.getLogger(ProxyCenter.class);
	
	public static boolean isStart = false;
	
	public final static ThreadLocal<Proxy> threadLocal = new ThreadLocal<>();
	
	public final static Object lock = new Object();
	
	public static void start(ProxyConfig config){
		synchronized (lock) {
			if(!isStart){
				Constants.PROXY_QUEUE = new ArrayBlockingQueue<Proxy>(config.getMinProxyNum()+config.getSpareProxyNum());
				
				Constants.ABLE_USE_PROXY_QUEUE = new ArrayBlockingQueue<Proxy>(config.getSpareProxyNum());
				
				try {
					Reflections reflections = new Reflections("com.hao.proxy.crawler");
					Set<Class<? extends AbstractCrawler>> classes = reflections.getSubTypesOf(AbstractCrawler.class);
					for(Class<? extends AbstractCrawler> clazz : classes) {
						Constants.THREAD_POOL.execute(clazz.newInstance());
					}
					ProxyFilter.startFilter(config);
					isStart = true;
				}
				catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
	}
	
	
	
	public static Proxy getProxy(){
		Proxy proxy = threadLocal.get();
		try {
			if(proxy==null || ProxyStatusEnum.USING!=proxy.getStatus()){
				while(!isStart){
					Sleep.sleep(1000);
				}
				proxy = Constants.ABLE_USE_PROXY_QUEUE.take();
				proxy.setStatus(ProxyStatusEnum.USING);
				proxy.setThreadName(Thread.currentThread().getName());
				threadLocal.set(proxy);
			}
			
			if(ProxyStatusEnum.ERROR!=proxy.getStatus() && !Constants.PROXY_QUEUE.contains(proxy)){
				Constants.PROXY_QUEUE.offer(proxy);
			}
		}
		catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return proxy;
	}
	
	public static Proxy getProxyFromPool(){
		Proxy proxy = null;
		try {
			while(!isStart){
				Sleep.sleep(1000);
			}
			proxy = Constants.PROXY_QUEUE.take();
			Constants.PROXY_QUEUE.add(proxy);
		}
		catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return proxy;
	}
	
}
